home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
315_01
/
fft.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-14
|
14KB
|
566 lines
/* int_scale(), dbl_scale(), and long_scale() moved from herc.c */
/* 10/89, because herc.c is being discontinued, and msherc.com is */
/* being used for hercules graphcis support. T Clune */
/* fft.c is a file of functions to support fourier transforms. */
/* Written 3/89 by T Clune. Copyright (c) 1989, Eye Research Institute, */
/* 20 Staniford St, Boston, MA 02114. All Rights Reserved. */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <malloc.h>
#include <conio.h>
#include "fft.h"
/* data_multiply() multiplies two data files of equal length together */
void data_multiply(file1, file2)
char file1[], file2[];
{
FILE *f1, *f2, *f3;
char string[80];
int i, numpts1, numpts2;
double d1, d2, *d_out, minval, maxval;
f1=fopen(file1,"r");
if(f1==NULL)
{
printf("Error opening data file. Exiting routine.\n");
printf("Press any key to continue...\n");
mgetch();
return;
}
f2=fopen(file2,"r");
if(f2==NULL)
{
printf("Error opening data file. Exiting routine.\n");
printf("Press any key to continue...\n");
mgetch();
return;
}
fscanf(f1,"%d %*lf %*lf", &numpts1);
fscanf(f2,"%d %*lf %*lf", &numpts2);
if(numpts1 != numpts2)
{
printf("Different size input files. Exiting routine.\n");
printf("Press any key to continue...\n");
mgetch();
return;
}
while(kbhit()) ;
printf("Enter filespec for output file\n");
mgets(string);
f3=fopen(string,"w");
if(f3==NULL)
{
printf("Error opening output file. Exiting routine.\n");
printf("Press any key to continue...\n");
mgetch();
return;
}
d_out=(double *)malloc(sizeof(double)*numpts1);
if(d_out==NULL)
{
printf("malloc() error in data_multiply(). Program aborting.\n");
exit(-1);
}
for(i=0;i<numpts1;i++)
{
fscanf(f1,"%lf", &d1);
fscanf(f2,"%lf",&d2);
d_out[i]=d1*d2;
}
minmax(d_out,numpts1,&minval,&maxval);
fprintf(f3,"%d %f %f\n", numpts1, minval, maxval);
for(i=0;i<numpts1;i++)
fprintf(f3,"%f\n",d_out[i]);
fclose(f1);
fclose(f2);
fclose(f3);
free(d_out);
}
/* dbl_scale() scales an extended precision floating point number */
/* to an integer value. It is useful for scaling floating point */
/* numbers for graphing on the screen. */
/* moved from herc.c 10/89 by T Clune */
int dbl_scale(val, min, max, out_min, out_max)
double val, min, max; /* val= number to be scaled; min= smallest possible */
/* value for val; max=largest possible value */
int out_min, out_max; /* out_min=integer to return if val=min; */
/* out_max=integer to return if val=max. NOTE THAT out_min */
/* MAY BE LARGER THAN out_max. If you want to change screen */
/* values from 4th quadrant to 1st quadrant, the y-value */
/* out_min would be larger than the y-value out_max, while */
/* x-value out_max would be larger than the x-value out_min */
{
int out_val, largest, smallest; /* val returned, larger of out_min */
/* and out_max, smaller of the same */
double scale_factor; /* ratio of in and out ranges */
/* scale the input value */
scale_factor = (out_max - out_min) / (max - min);
out_val = (int)((val - min) * scale_factor + out_min);
if(out_min>out_max) /* check for max/min inversion */
{
smallest = out_max;
largest = out_min;
}
else
{
smallest = out_min;
largest = out_max;
}
if(out_val > largest) /* check for out-of-bounds values */
out_val = largest; /* since val is not checked to insure */
if(out_val < smallest) /* that it is between min and max, this */
out_val = smallest; /* is necessary. By checking at the last */
/* step, any arithmetic round-off accumulation */
/* is also trapped */
return out_val; /* return the scaled value */
}
/* fft() accepts the time-domain data x,y (n points, where n is a power of 2) */
/* and converts to frequency domain rectangular data if flag==FORWARD, */
/* or accepts frequency-domain data in x,y and converts to time domain if */
/* flag==INVERSE. FORWARD and INVERSE are defined in fft.h */
void fft(x, y, n, flag)
double x[], y[];
int n, flag;
{
int maxpower, arg, pnt0, pnt1;
int i, j=0, a, b, k;
double prodreal, prodimag, harm, temp;
double *cos_coef;
double *sin_coef;
cos_coef=(double*)calloc(n,sizeof(double));
sin_coef=(double*)calloc(n,sizeof(double));
if((cos_coef==NULL) || (sin_coef==NULL))
{
printf("malloc() error in fft function\n");
if(cos_coef != NULL)
free(cos_coef);
if(sin_coef != NULL)
free(sin_coef);
return;
}
if(flag==INVERSE)
{
for (i=0;i<n;i++)
{
x[i] /=n;
y[i] /=n;
}
}
for(i=0;i<(n-1);i++)
{
if(i<j)
{
temp=x[i];
x[i]=x[j];
x[j]=temp;
temp=y[i];
y[i]=y[j];
y[j]=temp;
}
k=n/2;
while(k<=j)
{
j -=k;
k /=2;
}
j +=k;
}
maxpower=0;
i=n;
while(i>1)
{
maxpower++;
i /=2;
}
harm=2*PI/n;
for(i=0;i<n;i++)
{
sin_coef[i]=flag*sin(harm*i);
cos_coef[i]=cos(harm*i);
}
a=2;
b=1;
for(j=0;j<maxpower;j++)
{
pnt0=n/a;
pnt1=0;
for(k=0;k<b;k++)
{
i=k;
while(i<n)
{
arg=i+b;
if(k==0)
{
prodreal=x[arg];
prodimag=y[arg];
}
else
{
prodreal=x[arg]*cos_coef[pnt1]-y[arg]*sin_coef[pnt1];
prodimag=x[arg]*sin_coef[pnt1]+y[arg]*cos_coef[pnt1];
}
x[arg]=x[i]-prodreal;
y[arg]=y[i]-prodimag;
x[i] +=prodreal;
y[i] +=prodimag;
i +=a;
}
pnt1 +=pnt0;
}
a *=2;
b *=2;
}
free(cos_coef);
free(sin_coef);
}
/* get_filter() builds a high_pass or low_pass filter. The arguments are: */
/* FILTER is the array for the filter coefficients (frequency-domain */
/* AMPLITUDE coefficients [0 to 1]), N is the number of elements in FILTER */
/* SIGN is -1 for lowpass, +1 for highpass; NYQUIST is the nyquist freq */
/* for the FILTER data set, CUTOFF is the filter cutoff frequency */
/* ROLLOFF is the rolloff in dBells per filter_unit; */
/* FILTER_UNIT is 2.0 for rolloff as dB/octave or 10.0 for dB/decade; */
/* get_filter() will create positive/negative format amplitude filter */
/* coefficients ONLY. The function returns the coefficients in FILTER */
double * get_filter(filter, n, sign, nyquist, cutoff, rolloff, filter_units)
double filter[];
int n, sign;
double nyquist, cutoff, rolloff, filter_units;
{
double freq_interval, active_freq;
double half_power, exp_var, octaves;
double filter_factor;
int i,m;
half_power=sqrt(0.5);
filter_factor = log10(filter_units);
m=n/2;
freq_interval=nyquist/m;
if(sign== (-1))
filter[0]=1.0;
else
filter[0]=0.0;
for(i=1;i<=m;i++)
{
active_freq=freq_interval*i;
/* number of octaves: */
octaves=log10(active_freq/cutoff)/filter_factor;
/* 20=constant for dB formula as amplitude */
exp_var=rolloff*octaves*sign/20.0;
exp_var=pow(10.0,exp_var);
filter[i]=exp_var*half_power;
if(filter[i]>1.0)
filter[i]=1.0;
if(filter[i]<MINVAL)
filter[i]=0.0;
if(sign==(-1) && filter[i]==0.0)
for( ;i<=m;i++)
filter[i]=0.0;
if(sign==1 && filter[i]==1.0)
for( ;i<=m;i++)
filter[i]=1.0;
}
for(i=1;i<m;i++)
filter[m+i]=filter[m-i];
unscramble_transform(filter,n);
return filter;
}
/* int_scale() is a routine to scale integer values to fit graph */
/* moved from herc.c 10/89 by T Clune */
int int_scale(in_val, in_min, in_max, out_min, out_max)
/* NOTICE THAT ALL PARAMETERS ARE INT */
/* in_val = number to be scaled */
/* in_min = smallest possible in_val */
/* in_max = largest possible in_val */
/* out_min =